#pragma once
#include "dvo.h"
#include <vector>
#include <iostream>

class FibonacciSequence_ps : public dvo::ps::Transceiver<int, int>{
public:
  FibonacciSequence_ps() {items_.push_back(1);items_.push_back(1);}
protected:
  virtual void Process(int& nth_item){
    if(items_.size() > nth_item){
      Send(items_[nth_item]);
      return;
    }
    int result;
    for(int i=items_.size(); i < nth_item; ++i){
      result = items_[i-1] + items_[i-2];
      items_.push_back(result);
    }
    Send(result);
  }
private:
  std::vector<int> items_;
};

class FibonacciSequence_pl : public dvo::pl::Transceiver<int, int>{
public:
  FibonacciSequence_pl() {items_.push_back(1);items_.push_back(1);}
protected:
  virtual int Process(){
    int nth_item = Demand();
    if(items_.size() > nth_item){
      return items_[nth_item];
    }
    int result;
    for(int i=items_.size(); i < nth_item; ++i){
      result = items_[i-1] + items_[i-2];
      items_.push_back(result);
    }
    return result;
  }
private:
  std::vector<int> items_;
};

bool test_fb_ps()
{
  return true;
}

void run_fb_ps()
{
  FibonacciSequence_ps sequencer;
  dvo::ps::Socket<int> socket;
  int result = 4;
  socket >> std::function<void(int&)>([&] (int& value) {result = std::move(value);});
  *sequencer.Output() >> &socket;
  //sequencer.Input()->Transmit(4);
  12 >> *sequencer.Input();
  std::cout << "The 12th fibonacci number is " << result << std::endl;
}

bool test_fb_pl()
{
  return true;
}

void run_fb_pl()
{
  FibonacciSequence_pl sequencer;
  dvo::pl::Socket<int> socket;
  socket = std::function<int(void)>([&] () {return 12;});
  socket << sequencer.Input();
  int result;
  result << *sequencer.Output();
  std::cout << "The 12th fibonacci number is " << result << std::endl;
}